package com.imu.purse.modules.trade.service.impl;

import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.imu.constant.Constant;
import com.imu.core.base.BaseService;
import com.imu.datasources.DataSourceNames;
import com.imu.datasources.annotation.DataSource;
import com.imu.enums.OrderTypeStatus;
import com.imu.enums.PStatus;
import com.imu.enums.TradeType;
import com.imu.enums.TransStatus;
import com.imu.purse.modules.bitcoin.form.BitcoinForm;
import com.imu.purse.modules.bitcoin.form.YtfcoinForm;
import com.imu.purse.modules.trade.dao.FundMapper;
import com.imu.purse.modules.trade.dao.TradeInfoMapper;
import com.imu.purse.modules.trade.dto.TradeInfoDto;
import com.imu.purse.modules.trade.entity.FundEntity;
import com.imu.purse.modules.trade.entity.TradeInfoEntity;
import com.imu.purse.modules.trade.form.TransForm;
import com.imu.purse.modules.trade.service.TradeInfoService;
import com.xiaoleilu.hutool.bean.BeanUtil;
import com.xiaoleilu.hutool.collection.CollectionUtil;
import com.xiaoleilu.hutool.date.DatePattern;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.map.MapUtil;
import com.xiaoleilu.hutool.poi.excel.ExcelUtil;
import com.xiaoleilu.hutool.poi.excel.ExcelWriter;
import com.xiaoleilu.hutool.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
 * 交易明细
 * @author sunhongwei
 * @email sunhongwei@jshijian.com
 * @date 2018-03-22 10:33:20
 * Copyright (c) 2017 武汉极时间科技有限公司 版权所有 
 * Jshijian aloha CO.,LTD. All Rights Reserved. 
 */
@Service
public class TradeInfoServiceImpl extends BaseService<TradeInfoEntity> implements TradeInfoService
{
	@Override
    @Transactional
    public int save(final TradeInfoEntity tradeInfo)
	{
    	return super.insert(tradeInfo);
	}
	
	@Override
	@Transactional
    public int update(final TradeInfoEntity tradeInfo) 
    {
    	return mapper.updateByPrimaryKeySelective(tradeInfo);
    }
    
    @Override
	@Transactional
    public int saveUpdate(final TradeInfoEntity tradeInfo)
    {
    	int len = 0;
    	
    	if(1 > (len = this.update(tradeInfo)))
    	{
        	len = this.insert(tradeInfo);
    	}
    	
    	return len;
    }
    
 	@Override
	@Transactional
    public boolean delete(final String ...ids)
    {
    	if(ArrayUtil.isEmpty(ids)) return false;
    	
    	for (String id : ids) 
    	{
    		if(StrUtil.isBlank(id)) continue;
    		
    		if(NumberUtil.isNumber(id))
    		{
        		mapper.deleteByPrimaryKey(Long.valueOf(id));
    		}
		}
    	
    	return true;
    }
    
    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public TradeInfoEntity findById(final Long id)
    {
    	if(null == id) return null;
    	return mapper.selectByPrimaryKey(id);
    }
    
    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public List<TradeInfoEntity> queryList(final TradeInfoEntity tradeInfo)
    {
    	if (tradeInfo.getPage() != null && tradeInfo.getLimit() != null)
    	{
            PageHelper.startPage(tradeInfo.getPage(), tradeInfo.getLimit());
        }
    	
    	return mapper.findByPage(tradeInfo);
    }
    
    @Override
    @Transactional
	public void transferData(TransForm form) {
		List<Long> ids = Lists.newArrayList();
    	List<TradeInfoEntity> infoList = Lists.newArrayList();

    	Date nowDate = new Date();
    	//更新转出人金额
    	FundEntity fEntity = new FundEntity();
    	fEntity.setUserId(form.getPayUserId());
    	if(form.getOutFlag() && form.getRecUserId() == null){//属于外部转账(IMU转账到其他地方)
			//冻结转出人的金额
			fEntity.setFrozenMoney(form.getMoney().add(form.getFee()));
			fEntity.setTimeUpdate(nowDate);
			fundMapper.moFrozenMoney(fEntity);
			//交易信息
			TradeInfoEntity info = iniTradeInfoEntity(form,OrderTypeStatus.OUT.getType(),PStatus.Create.getType(),
					form.getPayUserId(),Constant.TRANSFER_OUT_ID,nowDate);
			infoList.add(info);
		}else if(form.getOutFlag() && form.getRecUserId() != null){//imu不同的核心钱包之间转账
			//冻结转出人的金额
			fEntity.setFrozenMoney(form.getMoney().add(form.getFee()));
			fEntity.setTimeUpdate(nowDate);
			fundMapper.moFrozenMoney(fEntity);
			//转出人
			//交易信息
			TradeInfoEntity info = iniTradeInfoEntity(form,OrderTypeStatus.OUT.getType(),PStatus.Create.getType(),
					form.getPayUserId(),form.getRecUserId(),nowDate);
			infoList.add(info);
			//接受人
			info = iniTradeInfoEntity(form,OrderTypeStatus.IN.getType(),PStatus.Create.getType(),
					form.getRecUserId(),form.getPayUserId(),nowDate);
			infoList.add(info);
		}else{//imu同一个核心钱包间转账
			//转出人
			fEntity.setMoney(form.getMoney().add(form.getFee()).multiply(new BigDecimal(-1)));
			fEntity.setTimeUpdate(nowDate);
			fundMapper.modMoneyByUId(fEntity);
			//接受人
			fEntity = new FundEntity();
			fEntity.setUserId(form.getRecUserId());
			fEntity.setMoney(form.getMoney());
			fEntity.setTimeUpdate(nowDate);
			fundMapper.modMoneyByUId(fEntity);
			//转出人
			//交易信息
			TradeInfoEntity info = iniTradeInfoEntity(form,OrderTypeStatus.OUT.getType(),PStatus.Finished.getType(),
					form.getPayUserId(),form.getRecUserId(),nowDate);
			infoList.add(info);
			//接受人
			info = iniTradeInfoEntity(form,OrderTypeStatus.IN.getType(),PStatus.Finished.getType(),
					form.getRecUserId(),form.getPayUserId(),nowDate);
			infoList.add(info);
		}

    	mapper.insertList(infoList);
		for(TradeInfoEntity info : infoList){
			ids.add(info.getId());
		}
		form.setIds(ids);
	}
    
    @Override
	@Transactional
	public void modBitData(List<BitcoinForm> fList) {
		// TODO Auto-generated method stub
		if(!CollectionUtils.isEmpty(fList)){
			for(BitcoinForm form : fList){
				//修改交易的信息
				int tNum = mapper.modByBitcoin(form);
				if(tNum == 0){//不存在，外部转入
					tNum = mapper.findCountByUTId(form);
					if(tNum == 0){//外部钱包转入到本钱包
						TradeInfoEntity tEntity = new TradeInfoEntity();
        				tEntity.setPayUserId(form.getUserId());
        				tEntity.setRecUserId(Constant.TRANSFER_OUT_ID);
        				tEntity.setOrderNo(DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"));
        				tEntity.setOrderType(OrderTypeStatus.OUT.getType());//默认为转出
        				if(form.getCategory().equalsIgnoreCase(Constant.TRANSFER_RECEIVE)){
							tEntity.setOrderType(OrderTypeStatus.IN.getType());
						}
        				tEntity.setOrderState(PStatus.Finished.getType());
        				tEntity.setMoney(form.getAmount().abs());
        				tEntity.setOrderCreate(new Date());
        				tEntity.setTransId(form.getTransId());
        				mapper.insert(tEntity);
        				//更新当前用户
        				fundMapper.modNoByUId(form);
					}
				}else{//钱包内部互转或不同钱包间转账
					//fee默认为0
					if(Constant.TRANSFER_SEND.equalsIgnoreCase(form.getCategory())){//转出者
						fundMapper.modByUId(form);
					}else{//接受者
						fundMapper.modNoByUId(form);
					}
				}
			}
		}
	}
	/**
	 * 构建交易信息
	 * @param form
	 * @param orderType
	 * @param orderState
	 * @param fromUId
	 * @param toUId
	 * @param nowDate
	 * @return
	 */
	private TradeInfoEntity iniTradeInfoEntity(TransForm form,Integer orderType, Integer orderState,Long fromUId,
											   Long toUId, Date nowDate){
		TradeInfoEntity info = new TradeInfoEntity();
		BeanUtil.copyProperties(form, info);
		info.setPayUserId(fromUId);
		info.setRecUserId(toUId);
		if(orderType == OrderTypeStatus.IN.getType()){//转入
			info.setRecAddr(form.getPayAddr());
			info.setRecPhone(form.getPayPhone());
		}
		info.setOrderType(orderType);
		info.setOrderState(orderState);
		info.setTransId(form.getTransId());
		info.setOrderCreate(nowDate);
		return info;
	}

	@Override
    @DataSource(name=DataSourceNames.SECOND)
    public List<TradeInfoEntity> queryLists(final TradeInfoEntity tradeInfo)
    {
    	if (tradeInfo.getPage() != null && tradeInfo.getLimit() != null)
    	{
            PageHelper.startPage(tradeInfo.getPage(), tradeInfo.getLimit());
        }
    	return mapper.findByPages(tradeInfo);
    }
	
	 @Override
   @DataSource(name=DataSourceNames.SECOND)
   public List<TradeInfoEntity> tradeSummaryList(final TradeInfoEntity tradeInfo)
   {
     if (tradeInfo.getPage() != null && tradeInfo.getLimit() != null)
     {
           PageHelper.startPage(tradeInfo.getPage(), tradeInfo.getLimit());
       }
     return mapper.findByPages2(tradeInfo);
   }
	
	

    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public void export(HttpServletResponse response, final TradeInfoEntity entity)
    {
    	List<TradeInfoEntity> entites = mapper.findByPages(entity);

    	TradeInfoDto dto = null;
    	List<TradeInfoDto> dtos = new ArrayList<TradeInfoDto>();
    	if(CollectionUtil.isNotEmpty(entites)){
			for (TradeInfoEntity  e : entites)
			{
				if(null == e || null == e.getId()) continue;
				dto = new TradeInfoDto();
				BeanUtil.copyProperties(e, dto);

				if(null != e.getOrderState()){
					dto.setOState(PStatus.getByType(e.getOrderState().intValue()));
				}
				if(null != e.getOrderType()){
					dto.setOType(OrderTypeStatus.getByType(e.getOrderType().intValue()));
				}
				if(null != e.getYtfType()){
					dto.setCType(TradeType.getByType(e.getYtfType().intValue()));
				}
				dto.setOTime(DateUtil.format(e.getOrderCreate(), DatePattern.NORM_DATETIME_FORMAT));
				dtos.add(dto);
			}
		}

    	//response为HttpServletResponse对象
    	response.setHeader("Content-disposition", "attachment; filename="+DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT)+".xls");//设置导出后的文件名称
    	response.setContentType("application/vnd.ms-excel;charset=utf-8"); 
    	
    	ExcelWriter writer = null;
    	ServletOutputStream out = null;
    	Map<String, String> alias = null;
    	
		try {
			// 通过工具类创建writer，默认创建xls格式
	    	writer = ExcelUtil.getWriter();
	    	//自定义标题别名
	    	alias = MapUtil.newHashMap();
	    	alias.put("phone", "付款用户");
	    	alias.put("recPhone", "收款用户");
	    	alias.put("orderNo", "订单号");
	    	alias.put("cType", "币种");
	    	alias.put("oType", "订单类型");
	    	alias.put("oState", "状态 ");
	    	alias.put("fee", "手续费");
	    	alias.put("smoney", "交易前数量");
	    	alias.put("money", "交易数量");
	    	alias.put("emoney", "交易后数量");
	    	alias.put("oTime", "交易时间");
	    	alias.put("detail", "描述");
	    	writer.setHeaderAlias(alias);
	    	//合并单元格后的标题行，使用默认标题样式
	    	writer.merge(alias.size()-1, "交易明细");
	    	// 一次性写出内容，使用默认样式
	    	writer.write(dtos);
			out = response.getOutputStream();
	    	writer.flush(out);
		} 
		catch (IOException ex) {
			ex.printStackTrace();
		}
		finally {// 关闭writer，释放内存
			if(null != writer) writer.close();
	    	if(null != out)
	    	{
		    	try { out.close(); } catch (IOException ie) {}
	    	}
		}
    }

	/**
	 * 以太坊外部转入
	 * @param form
	 * @return
	 */
	@Transactional
	public int modYtfInTranInfo(final YtfcoinForm form){
		TradeInfoEntity tradeInfoEntity = new TradeInfoEntity();
		tradeInfoEntity.setTransId(form.getTransId());
		tradeInfoEntity.setTransTime(form.getTransTime());
		tradeInfoEntity.setOrderState(TransStatus.FINISH.getType());
		tradeInfoEntity = mapper.getYtfOutByCon(tradeInfoEntity);
		if(tradeInfoEntity == null){
			FundEntity fundEntity = new FundEntity();
			fundEntity.setUserId(form.getUserId());
			fundEntity = fundMapper.selectOne(fundEntity);
			//查找该用户转出还未没有完成的总金额
			/*TradeInfoEntity tmpEntity = new TradeInfoEntity();
			tmpEntity.setPayUserId(form.getUserId());
			tmpEntity.setOrderType(OrderTypeStatus.OUT.getType());
			tmpEntity.setOrderState(TransStatus.CREATE.getType());
			BigDecimal nFMoney = mapper.getOutMoneyByUId(tmpEntity);*/
			BigDecimal sMoney = fundEntity.getMoney().subtract(fundEntity.getFrozenMoney());//更新前金额
			BigDecimal eMoney = sMoney.add(form.getMoney());

			//修改用户金额
			fundEntity = new FundEntity();
			fundEntity.setMoney(form.getMoney());
			fundEntity.setUserId(form.getUserId());
			fundEntity.setTimeUpdate(new Date());

			//插入一条记录
			//增加接受人账户金额
			fundMapper.addMoney(fundEntity);
			//获取该用户的金额

			//插入详情表
			String orderNo = DateUtil.format(new Date(),"yyyyMMddHHmmssSSS");
			Date nowDate = new Date();
			tradeInfoEntity = new TradeInfoEntity();
			tradeInfoEntity.setPayUserId(form.getUserId());
			tradeInfoEntity.setOrderNo(orderNo);
			tradeInfoEntity.setOrderType(OrderTypeStatus.IN.getType());
			tradeInfoEntity.setOrderState(TransStatus.FINISH.getType());
			tradeInfoEntity.setMoney(form.getMoney());
			tradeInfoEntity.setOrderCreate(nowDate);
			tradeInfoEntity.setTransId(form.getTransId());
			tradeInfoEntity.setRecAddr(form.getRecAddr());
			tradeInfoEntity.setYtfType(TradeType.IMU.getType());
			tradeInfoEntity.setSmoney(sMoney);
			tradeInfoEntity.setEmoney(eMoney);
			mapper.insert(tradeInfoEntity);
		}
		return 1;
	}

	/**
	 * 以太坊转出
	 * @param form
	 * @return
	 */
	@Transactional
	public int modYtfOutTransInfo(final YtfcoinForm form){
		//根据transId和时间修改trade_info
		TradeInfoEntity entity = new TradeInfoEntity();
		entity.setTransId(form.getTransId());
		entity.setOrderState(PStatus.Finished.getType());
		entity.setTransTime(form.getTransTime());
		if(mapper.modYtfOutTransInfo(entity) > 0){//代表存在
			entity = mapper.getYtfOutByCon(entity);
			//根据transId和时间修改trade_info,获取userId,money,fee
			//根据userId,money,fee修改imu_fund表
			FundEntity fEntity = new FundEntity();
			fEntity.setUserId(entity.getPayUserId());
			fEntity.setMoney(entity.getMoney().add(entity.getFee()));
			fundMapper.upYtfOutByUId(fEntity);
		}
		return 1;
	}

	@Transactional
	public int transOutData(final TransForm form){
		return mapper.upTIdById(form);
	}

	@Autowired
	private TradeInfoMapper mapper;
	
	@Autowired
	private FundMapper fundMapper;
}
